package cooperate

import (
	"gddgame.cc/galaxy/common/feature/orbit/chess_protocol"
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/serialize"
)

type OperateBuilder struct {
	execute *LogicExecute
	mapNoId string

	from   *structure.BaseData
	target *structure.BaseData

	all            []OperateData
	current        *UpdateOperateData
	operateMessage *OperateMessage
	contents       []UpdateOperateContent
}

// 简化operate的生成
func (logic *LogicExecute) OperateBuilder() *OperateBuilder {
	return &OperateBuilder{
		execute: logic,
	}
}

func (builder *OperateBuilder) BindMapNoId(mapNoId string) *OperateBuilder {
	builder.mapNoId = mapNoId
	return builder
}
func (builder *OperateBuilder) Target(target structure.BaseData) *OperateBuilder {
	builder.target = &target
	return builder
}
func (builder *OperateBuilder) From(from structure.BaseData) *OperateBuilder {
	builder.from = &from
	return builder
}
func (builder *OperateBuilder) Append(other *OperateBuilder) *OperateBuilder {
	other.update()
	if len(other.all) > 0 {
		builder.all = append(builder.all, other.all...)
	}
	return builder
}

func (builder *OperateBuilder) update() {
	if len(builder.contents) > 0 && builder.current != nil {
		builder.current.Operates = builder.contents
		b, _ := builder.current.MarshalMsg(nil)
		builder.all = append(builder.all, OperateData{
			Operate: BatchUpdateOperate,
			Data:    b,
		})
		builder.contents = builder.contents[0:0]
	}
}

func (builder *OperateBuilder) Data() []OperateData {
	builder.update()
	data := builder.all

	return data
}

func (builder *OperateBuilder) DataOfUpdate() []UpdateOperateContent {
	data := builder.contents

	return data
}
func (builder *OperateBuilder) Content() *OperateContent {
	builder.update()
	content := &OperateContent{
		MapNoId:  builder.mapNoId,
		Operates: builder.all,
		Message:  builder.operateMessage,
	}
	return content
}

func (builder *OperateBuilder) SendMessage(data *structure.BaseData, Event byte, content serialize.IStruct, param structure.ParamSlice) *OperateBuilder {
	var b []byte
	if content != nil {
		b, _ = content.MarshalMsg(nil)
	}
	builder.operateMessage = &OperateMessage{
		Data: data,
		Message: &DataMessage{
			Event:   Event,
			Content: b,
			Params:  param,
		},
	}
	return builder
}
func (builder *OperateBuilder) Operate(delay int64, check *CheckBuilder) {
	builder.update()
	var checkData [][]CheckData
	if check != nil {
		checkData = check.Data()
	}
	builder.execute.PushOperate(OperateContent{
		MapNoId:  builder.mapNoId,
		Checks:   checkData,
		From:     builder.from,
		Target:   builder.target,
		Operates: builder.all,
		Message:  builder.operateMessage,
	}, builder.execute.FormatTime(delay))
}

func (builder *OperateBuilder) CreateData(dataType structure.PublicDataType, id interface{}, position []byte, Extends [][]chess_protocol.ExtendItem, dependents map[string]interface{}) CreateOperateData {
	create := CreateOperateData{
		Data:       *structure.NewBaseData(dataType, id),
		Position:   position,
		Extends:    Extends,
		Dependents: nil,
	}
	if len(dependents) > 0 {
		d := []*DependentItem{}
		for dt, o := range dependents {
			depend := builder.execute.DefaultDepend(dataType, dt)
			if depend == nil {
				continue
			}
			be := depend.Be
			d = append(d, &DependentItem{
				Key:    dt,
				Depend: structure.NewBaseData(be.DependType, o),
			})
		}
		create.Dependents = d
	}
	return create
}

func (builder *OperateBuilder) Create(dataType structure.PublicDataType, id interface{}, position []byte, Extends [][]chess_protocol.ExtendItem, dependents map[string]interface{}) *OperateBuilder {
	create := builder.CreateData(dataType, id, position, Extends, dependents)
	builder.all = append(builder.all, NewOperateData(CreateOperate, &create))

	return builder
}

func (builder *OperateBuilder) Delete(dataType structure.PublicDataType, id interface{}) *OperateBuilder {
	delete := DeleteOperateData{}
	delete.DataType = dataType
	delete.Id = id
	builder.all = append(builder.all, NewOperateData(DeleteOperate, &delete))
	return builder
}
func (builder *OperateBuilder) Update(data structure.BaseData, check *CheckBuilder) *OperateBuilder {
	builder.update()
	var checkData [][]CheckData
	if check != nil {
		checkData = check.Data()
	}
	builder.current = &UpdateOperateData{
		Data:   data,
		Checks: checkData,
	}
	return builder
}

func (builder *OperateBuilder) ChangeData(key string, value interface{}) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Value:   value,
		Operate: ChangeData,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) ChangeDateTime(key string, delay int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Value:   delay,
		Operate: ChangeDateTime,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) ChangePosition(position []byte) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     Position,
		Value:   position,
		Operate: ChangePosition,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) ChangeIgnore(ignore bool) *OperateBuilder {
	content := UpdateOperateContent{
		Value:   ignore,
		Operate: ChangeIgnore,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) IncrData(key string, value int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Operate: IncrData,
		Value:   value,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) IncrDataGreater(key string, value int, greater int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Operate: IncrDataGreater,
		Value:   value,
		Index:   greater,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) IncrDataLesser(key string, value int, lesser int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Operate: IncrDataLesser,
		Value:   value,
		Index:   lesser,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) IncrDataGreaterSync(key string, value int, greater int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Operate: IncrDataGreaterSync,
		Value:   value,
		Index:   greater,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) IncrDataLesserSync(key string, value int, lesser int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Operate: IncrDataLesserSync,
		Value:   value,
		Index:   lesser,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) ChangeList(extend string, index int, value interface{}) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: ChangeList,
		Value:   value,
		Index:   index,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) ChangeListTime(extend string, index int, second int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: ChangeListTime,
		Value:   second,
		Index:   index,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) IncrList(extend string, index int, value int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: IncrList,
		Value:   value,
		Index:   index,
	}
	builder.contents = append(builder.contents, content)
	return builder
}
func (builder *OperateBuilder) IncrListFrom(extend string, index int, from int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: IncrFromList,
		Value:   from,
		Index:   index,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) AddSet(extend string, value int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: AddSet,
		Value:   value,
		Index:   0,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) RemoveSet(extend string, value int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: RemoveSet,
		Value:   value,
		Index:   0,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) AddSorted(extend string, value interface{}, sort int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: AddSorted,
		Value:   value,
		Index:   sort,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) RemoveSorted(extend string, value interface{}) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: RemoveSorted,
		Value:   value,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) AddTimeSorted(extend string, value interface{}, delaySecond int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: AddTimeSorted,
		Value:   value,
		Index:   delaySecond,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) RemoveTimeSorted(extend string, value interface{}) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     extend,
		Operate: RemoveTimeSorted,
		Value:   value,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) ClearTimeSorted(extend structure.ExtendType, tt int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     utils.ToString(extend),
		Operate: ClearTimeSorted,
		Index:   tt,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) AddDepend(dependKey string, dataType structure.PublicDataType, id interface{}) *OperateBuilder {
	content := UpdateOperateContent{
		Operate: AddDepend,
		Value:   id,
		Index:   int(dataType),
		Key:     dependKey,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) RemoveDepend(dependKey string, dataType structure.PublicDataType, id interface{}) *OperateBuilder {
	content := UpdateOperateContent{
		Operate: RemoveDepend,
		Value:   id,
		Index:   int(dataType),
		Key:     dependKey,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

// 重置任务时间
func (builder *OperateBuilder) ResetSchedule(key string, time float32, delay int) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Operate: ResetSchedule,
		Value:   int(time * 1000),
		Index:   delay * 1000,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

// 保持任务时间，但需要重新处理
func (builder *OperateBuilder) HoldSchedule(key string, schedule *ScheduleBuilder) *OperateBuilder {
	b := schedule.Data()
	content := UpdateOperateContent{
		Key:     key,
		Operate: HoldSchedule,
		Value:   b,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) RemoveSchedule(key string) *OperateBuilder {
	content := UpdateOperateContent{
		Key:     key,
		Operate: RemoveSchedule,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

//func (builder *OperateBuilder) BindEvent(eventData structure.EventData, e byte) *OperateBuilder {
//	content := UpdateOperateContent{
//		Key:     utils.ToString(eventData.Content),
//		Operate: BindEvent,
//		Index:   int(eventData.Mode),
//		Value:   e,
//	}
//	builder.contents = append(builder.contents, content)
//	return builder
//}
//
//func (builder *OperateBuilder) LinkEvent(e byte, ee SystemEvent) *OperateBuilder {
//	content := UpdateOperateContent{
//		Operate: LinkEvent,
//		Index:   int(ee),
//		Value:   e,
//	}
//	builder.contents = append(builder.contents, content)
//	return builder
//}
//
func (builder *OperateBuilder) ClearEvent(e byte, system byte) *OperateBuilder {
	content := UpdateOperateContent{
		Operate: ClearEvent,
		Value:   e,
		Index:   int(system),
	}
	builder.contents = append(builder.contents, content)
	return builder
}

//
//func (builder *OperateBuilder) UnLinkEvent(ee SystemEvent) *OperateBuilder {
//	content := UpdateOperateContent{
//		Operate: UnLinkEvent,
//		Index:   int(ee),
//	}
//	builder.contents = append(builder.contents, content)
//	return builder
//}

func (builder *OperateBuilder) AddRelation(relation string, dataType structure.PublicDataType, id interface{}) *OperateBuilder {
	content := UpdateOperateContent{
		Operate: AddRelation,
		Index:   int(dataType),
		Value:   id,
		Key:     relation,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) RemoveRelation(relation string, dataType structure.PublicDataType, id interface{}) *OperateBuilder {
	content := UpdateOperateContent{
		Operate: RemoveRelation,
		Index:   int(dataType),
		Value:   id,
		Key:     relation,
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) AddLink(relation string, dataType structure.PublicDataType, id interface{}, reverse bool) *OperateBuilder {
	content := UpdateOperateContent{
		Operate: AddLink,
		Index:   int(dataType),
		Value:   id,
		Key:     relation,
	}
	if reverse {
		content.Operate = AddToLink
	}
	builder.contents = append(builder.contents, content)
	return builder
}

func (builder *OperateBuilder) RemoveLink(relation string, dataType structure.PublicDataType, id interface{}, reverse bool) *OperateBuilder {
	content := UpdateOperateContent{
		Operate: RemoveLink,
		Index:   int(dataType),
		Value:   id,
		Key:     relation,
	}
	if reverse {
		content.Operate = RemoveFromLink
	}
	builder.contents = append(builder.contents, content)
	return builder
}
